///////////////////////////////////////////////////////////////////////////
// 
// AutoUpdater
// 
// Copyright 2008 ARTSTAFF CO.,LTD. 
// All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////
package jp.co.artstaff.updater
{
import air.net.URLMonitor;

import flash.desktop.NativeApplication;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.StatusEvent;
import flash.net.URLRequest;

import mx.controls.Alert;
import mx.events.CloseEvent;
	

//--------------------------------------------------------------------------
//
//  Dispatch Events
//
//--------------------------------------------------------------------------
/**
 * アップデートチェック終了（Update不要）時にディスパッチされます
 */
[Event(name="autoupdateevent_update_unnecessary"
    , type="jp.co.artstaff.updater.AutoUpdateEvent")]

/**
 * アップデートチェック終了（ユーザによるアップデート拒否）時にディスパッチされます
 */
[Event(name="autoupdateevent_update_cancel"
    , type="jp.co.artstaff.updater.AutoUpdateEvent")]

/**
 * AutoUpdateManager
 * 
 */
public class AutoUpdateManager extends EventDispatcher
{
    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    // アップデータクラス
    //----------------------------------
    protected var __autoupdater:AutoUpdater;

    //----------------------------------
    // URLモニタ（アップデートサーバ監視用）
    //----------------------------------
    private var _urlMonitor:URLMonitor;

    //----------------------------------
    // 設定情報
    //----------------------------------
    private var _config:AutoUpdateConfig;

    //----------------------------------
    // Alert等を表示する際の親オブジェクト
    //----------------------------------
    protected var __parent:Sprite;

    //--------------------------------------------------------------------------
    //
    //  Properties(getter/setter)
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    // バージョン文字列
    //----------------------------------
    private var _applicationVersion:String = "0.00";
    /**
     * 
     * @return　バージョン番号（文字列） 
     * 
     */
    public function get applicationVersion():String
    {
        return _applicationVersion;
    }


    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

    /**
     * Constructor
     * 
     * @param config 設定情報
     * @param parent alert等を表示する際の親となるオブジェクト
     * 
     */
    public function AutoUpdateManager(config:AutoUpdateConfig, parent:Sprite)
    {
    	_config = config;
        __parent = parent;
    }

    /**
     * 自動更新処理
     * 
     * ※オーバライド厳禁
     * ※この処理は、（本体アプリケーションと）非同期で実行されます。
     * 
     */
    public function update():void
    {
        // ADFファイルからバージョン番号取得
        var adfXml:XML = NativeApplication.nativeApplication.applicationDescriptor;
        var adfXmlNs:Namespace = adfXml.namespace();
        _applicationVersion = adfXml.adfXmlNs::version;
        
        // アップデータへのイベント登録
        __autoupdater = new AutoUpdater(_config);
        __autoupdater.addEventListener(
            AutoUpdateEvent.GET_VERSION_COMPLETE,_getVersionCompleteHandler);
        __autoupdater.addEventListener(
            AutoUpdateEvent.GET_VERSION_FAULT,_getVersionFaultHandler);
        __autoupdater.addEventListener(
            AutoUpdateEvent.UPDATE_AIRFILE_FAULT,_updateAirFileFaultHandler);

        // ソケットモニタ（アップデートサーバ監視用）起動
        _urlMonitor 
            = new URLMonitor(
                new URLRequest(__autoupdater.getVersionDefineFileUrl())
            );
        _urlMonitor.addEventListener(StatusEvent.STATUS,_urlMonitorStatusChangeHandler);
        _urlMonitor.start();

    }

    //--------------------------------------------------------------------------
    //
    //  Event handlers
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    // ソケットモニタ（アップデートサーバ監視用）状態変更
    //----------------------------------
    private function _urlMonitorStatusChangeHandler(event:StatusEvent):void
    {
        if(_urlMonitor.available)
        {
            // OFF→ON

            // モニター止める
            _urlMonitor.stop();
            // 最新バージョン番号取得
            __autoupdater.getVersion();
        }
        else
        {
            // ON→OFF
        }
    }

    //----------------------------------
    // 最新バージョン番号取得完了
    //----------------------------------
    private function _getVersionCompleteHandler(event:AutoUpdateEvent):void
    {
        try
        {
            // バージョン比較（クライアント値<->サーバからの取得値）
            if(__autoupdater.isLatestApp(applicationVersion)){
                // 最新バージョンの場合・・・ここまで処理が流れたら、アプリ利用OKとする。
                // アップデート不要である旨、イベントスロー
                dispatchEvent(new AutoUpdateEvent(AutoUpdateEvent.UPDATE_UNNECESSARY));
                return;
            }

            // 最新バージョンでない場合・・・最新版のアプリをDLし、アップデートするか確認。
            __confirmUpdate();
        }
        catch(error:Error){
            trace(error.getStackTrace());
            __handleUpdateError("最新バージョン情報取得中に\nエラーが発生しました。");
        }
    }

    //----------------------------------
    // 最新バージョン番号取得失敗
    //----------------------------------
    private function _getVersionFaultHandler(event:AutoUpdateEvent):void
    {
        __handleUpdateError("最新バージョン情報取得中に\nエラーが発生しました。");
    }

    //----------------------------------
    // AIRファイルアップデート失敗
    //----------------------------------
    private function _updateAirFileFaultHandler(event:AutoUpdateEvent):void
    {
        __handleUpdateError("最新バージョンの\nダウンロードに失敗しました。");
    }

    /**
     * 現バージョンが最新でない場合にとる処置を記述します。
     * デフォルトの挙動は、Alert(OK/Cancel)にてアップデート確認をおこないます。
     * 挙動を変えたい場合には、このメソッドをオーバライドしてください 
     * 
     */
    protected function __confirmUpdate():void
    {
        // （デフォルトの動作）
        // 最新バージョンでない場合・・・最新版のアプリをDLし、アップデートするかどうか確認。
        Alert.show(
            "新バージョンがリリースされました。\nアップデートしますか？\n　＊現バージョン："
                + this.applicationVersion
                + "\n　＊新バージョン："
                + __autoupdater.getLatestVersionStr()
            ,"アップデート"
            ,Alert.YES | Alert.NO
            ,__parent
            ,__confirmUpdateCloseHandler);
    }

    //----------------------------------
    // アップデート実行確認ダイアログクローズ
    // （オーバライド可）
    //----------------------------------
    protected function __confirmUpdateCloseHandler(event:CloseEvent):void
    {
        if(event.detail == Alert.YES)
        {
            __autoupdater.loadAirFile();
        }
        else
        {
            // アップデートキャンセルである旨、イベントスロー
            dispatchEvent(new AutoUpdateEvent(AutoUpdateEvent.UPDATE_CANCEL));
        }
    }

    /**
     * アップデートにおけるエラー発生時の処理を記述します。
     * デフォルトの挙動は、Alert(OK)を表示した後、アプリケーションを終了させます。
     * 挙動を変えたい場合には、このメソッドをオーバライドしてください 
     * 
     * @param msg エラー時のメッセージ
     */
    protected function __handleUpdateError(msg:String):void
    {
    	// ダイアログを表示して、アプリケーション終了
        Alert.show(msg + "\nアプリケーションを終了します。","エラー",Alert.OK, __parent, __exitApp);
    }

    //----------------------------------
    // ワーニング発生時処理
    // （オーバライド可）
    //----------------------------------
    /**
     * アップデートにおけるワーニング発生時の処理を記述します。
     * デフォルトの挙動は、Alert(OK)を表示した後、アプリケーションを続行します。
     * 挙動を変えたい場合には、このメソッドをオーバライドしてください 
     * 
     * @param msg 警告時のメッセージ
     * 
     */
    protected function __handleUpdateWarning(msg:String):void
    {
        // ダイアログを表示するが、アプリケーション続行
        Alert.show(msg,"警告", Alert.OK, __parent);
    }

    //----------------------------------
    // アプリケーション終了
    //----------------------------------
    protected function __exitApp(event:Event):void
    {
        NativeApplication.nativeApplication.exit(0);
    }
}
}